/*******************************************************************************
 * This file is part of TERMINAL RECALL
 * Copyright (c) 2012-2014 Chuck Ritola
 * Part of the jTRFP.org project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     chuck - initial API and implementation
 ******************************************************************************/
package org.jtrfp.trcl.obj;

import java.util.Comparator;
import java.util.TreeSet;

import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.jtrfp.trcl.RenderableSpacePartitioningGrid;
import org.jtrfp.trcl.core.TRFactory.TR;
import org.jtrfp.trcl.math.Misc;
import org.jtrfp.trcl.obj.Smoke.SmokeType;

public class SmokeSystem extends RenderableSpacePartitioningGrid{
    	private final int MAX_SMOKE_PER_POOL=80;
    	private final Smoke[][] allSmokes = new Smoke[SmokeType.values().length][];
    	private final int [] indices = new int[SmokeType.values().length];
	public SmokeSystem(String debugName){
	    super();
	    int i;
	    for(SmokeType t:SmokeType.values()){
		final int ordinal = t.ordinal();
		allSmokes[ordinal]=new Smoke[MAX_SMOKE_PER_POOL];
		for(i=0; i<MAX_SMOKE_PER_POOL; i++){
			allSmokes[ordinal][i]=new Smoke(t,"SmokeSystem."+debugName);
		    }//end for(MAX_SMOKE_PER_POOL)
	    }//end for(SmokeType s)
	}//end constructor()
	public Smoke triggerSmoke(Vector3D pos, SmokeType type) {
	    if(!isNewSmokeFeasible(pos,type))
		return null;
	    final int ordinal = type.ordinal();
	    indices[ordinal]++;indices[ordinal]%=MAX_SMOKE_PER_POOL;
	    Smoke result = allSmokes[ordinal][indices[ordinal]];
	    result.reset();
	    result.setPosition(pos.toArray());
	    add(result);
	    return result;
	}//end triggerSmoke()
	
    private boolean isNewSmokeFeasible(final Vector3D loc, SmokeType type) {
	final TreeSet<Smoke> proximalSmokes = new TreeSet<Smoke>(
		new Comparator<Smoke>() {
		    @Override
		    public int compare(Smoke o1, Smoke o2) {
			return Misc.satCastInt(o1.getTimeOfLastReset()
				- o2.getTimeOfLastReset());
		    }
		});
	for (int smokeTypeIndex = 0; smokeTypeIndex < allSmokes.length; smokeTypeIndex++) {
	    Smoke[] explosionsOfThisType = allSmokes[smokeTypeIndex];
	    for (Smoke thisSmoke : explosionsOfThisType) {
		if (thisSmoke.isActive()) {
		    final double distance = new Vector3D(
			    thisSmoke.getPosition()).distance(loc);
		    if (distance < 1000)
			return false;
		    if (distance < OneShotBillboardEvent.PROXIMITY_TEST_DIST)
			proximalSmokes.add(thisSmoke);
		}// end if(isActive)
	    }// end for(explosionsOfThisType)
	}// end for(explosions)
	if (proximalSmokes.size() + 1 > OneShotBillboardEvent.MAX_PROXIMAL_EVENTS)
	    proximalSmokes.first().destroy();// Destroy oldest
	return true;
    }// end isNewSmokeFeasible(...)
}//end SmokeFactory
